<?php
/**
 * Fsockopen 封装类
 *
 * @version 1.0
 *
 * @author CoseyLee@gmail.com
 *
 */

class sockopen_url
{
	protected $host = ''; // 主机
	protected $protocol = ''; // 网络协议
	protected $port = ''; // 端口
	protected $user_agent = ''; // UA
	protected $headers = ''; // 头信息
	protected $errno = 0; // 错误号
	protected $errstr = ''; // 错误信息

	/**
	 * 构造方法
	 * 
	 * @param $user_agent 设置 User Agent
	 */
	public function __construct($user_agent = '')
	{
		if (empty($user_agent))
		{
			$this -> user_agent = $_SERVER['HTTP_USER_AGENT'];
		}
		else
		{
			$this -> user_agent = $user_agent;
		}
	}
	
	/**
	 * 设置连接的主机
	 * 
	 * @param $host 主机 （可以使用 ssl://www.domain.com）
	 * @param $port 端口
	 */
	public function setHost($host, $port = 80)
	{
		if (substr($host, 0, 6) == 'ssl://')
		{
			$this -> host = substr($host, 6);
			$this -> protocol = 'ssl://';
		}
		else
		{
			$this -> host = $host;
			$this -> protocol = '';
		}
		$this -> port = $port;
	}

	/**
	 * 设置自定义头信息
	 * 
	 * @param $header 头信息可以为数组或字符串
	 */
	public function setHeader($header)
	{
		if (is_array($header))
		{
			$header = implode("\r\n", $header);
		}
		$header = $header."\r\n";
		$this -> headers .= $header;
	}

	/**
	 * GET 方法
	 * 
	 * @param $path 请求的路径
	 * @param $timeout 超时时间
	 */
	public function _GET($path, $timeout = 5)
	{
		$out = "GET {$path} HTTP/1.0\r\n";
		$out .= "Accept: */*\r\n";
		$out .= "Accept-Language: zh-cn\r\n";
		$out .= "User-Agent: {$this -> user_agent}\r\n";
		$out .= "Host: {$this -> host}\r\n";
		$out .= "Connection: Close\r\n";
		$out .= $this -> headers;
		$out .= "\r\n";

		return $this -> exec($out, $timeout);
	}

	/**
	 * POST 方法
	 * 
	 * @param $path 请求的路径
	 * @param $post 发送的数据可以是数组形式
	 * @param $timeout 超时时间
	 */
	public function _POST($path, $post = '', $timeout = 5, $content_type = 'application/x-www-form-urlencoded')
	{
		if(is_array($post))
		{
			$post = http_build_query($post);
		}

		$out = "POST {$path} HTTP/1.0\r\n";
		$out .= "Accept: */*\r\n";
		$out .= "Accept-Language: zh-cn\r\n";
		$out .= "Content-Type: {$content_type}\r\n";
		$out .= "User-Agent: {$this -> user_agent}\r\n";
		$out .= "Host: {$this -> host}\r\n";
		$out .= 'Content-Length: '.strlen($post)."\r\n";
		$out .= "Connection: Close\r\n";
		$out .= $this -> headers;
		$out .= "\r\n";
		$out .= $post;

		return $this -> exec($out, $timeout);
	}

	/**
	 * UPLOAD 上传文件
	 * 
	 * @param $path 请求的路径
	 * @param $post 发送的数据（数组形式）
	 * @param $files 要上传的文件，多维数组 array('input' => '表单名称用于接收', 'name' => '文件名称', 'filedata' => '文件数据')
	 * @param $timeout 超时时间
	 */
	public function _UPLOAD($path, $post = array(), $files = array(), $timeout = 5)
	{
		if (empty($files)) return false;
		
		$key = md5(time());
		$data = "\r\n";
		foreach ($post as $name => $value)
		{
			$data .= '------'.$key."\r\n";
			$data .= 'Content-Disposition: form-data; name="'.$name."\"\r\n\r\n";
			$data .= $value."\r\n";
		}
		foreach ($files as $file)
		{
			$data .= '------'.$key."\r\n";
			$data .= 'Content-Disposition: form-data; name="'.$file['input']."\"; filename=\"".$file['name']."\"\r\n";
			$data .= "Content-Type: application/octet-stream\r\n\r\n";
			$data .= "{$file['filedata']}\r\n";
			$data .= "------{$key}--\r\n";
		}
		$data .= "\r\n";
		
		$out = "POST {$path} HTTP/1.0\r\n";
		$out .= "Accept: */*\r\n";
		$out .= "Accept-Language: zh-cn\r\n";
		$out .= "Content-Type: multipart/form-data; boundary=----{$key}\r\n";
		$out .= "User-Agent: {$this -> user_agent}\r\n";
		$out .= "Host: {$this -> host}\r\n";
		$out .= 'Content-Length: '.(strlen($data))."\r\n";
		$out .= "Connection: Close\r\n";
		$out .= $this -> headers;
		$out .= $data;
		$out .= "\r\n";
		
		return $this -> exec($out, $timeout);
	}
	
	/**
	 * 开启连接
	 * 
	 * @param $out 写入信息
	 * @param $timeout 超时时间
	 */
	protected function exec($out, $timeout)
	{
		$fp = @fsockopen($this -> protocol.$this -> host, $this -> port, $this -> errno, $this -> errstr, $timeout);
		if ($fp == true)
		{
			stream_set_blocking($fp, true);
			fwrite($fp, $out);
			$reponse = '';
			while(!feof($fp))
			{
				$reponse .= fgets($fp, 10240);
			}
			fclose($fp);
			$reponse = explode("\r\n\r\n", $reponse, 2);
			return $reponse;
		}
		else
		{
			return false;
		}
	}

	/**
	 * 获取错误信息
	 * 
	 */
	public function getError()
	{
		return array('error' => $this -> errstr, 'errno' => $this -> errno);
	}
}